package com.jiangruan.javaproject.address;

import com.jiangruan.javaproject.hashUtils.Base58;
import com.jiangruan.javaproject.hashUtils.Hash;

import java.security.*;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECPoint;
import java.util.Arrays;

/**
 * @author:huayuzhuo
 * @email:2798866329@qq.com
 * @desc:   该类用于生成原始格式的比特币地址
 * @datatime: 2021/12/20 14:28
 */
public class Address {

/**
 * 生成随机椭圆密钥对
 * */

    public static KeyPair generateKeys(){

        try {                                       //公用的算法
            KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
            ECGenParameterSpec spec = new ECGenParameterSpec("secp256k1");
            generator.initialize(spec);
            return generator.generateKeyPair();
        } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
        return null;
    }


/**
* 根据密钥对生成比特币地址
* */
    public static String newAddress(KeyPair keyPair){

        ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();
        ECPoint point = publicKey.getW();

        //获得公钥
        byte[] pubKey = toUncompressPukey(point);

        byte[] pubKeyHash256 = Hash.SHA256(pubKey);
        byte[] pubHash160 = Hash.RIPEMD160(pubKeyHash256);

        //assert pubHash160 != null;          //断言此变量不为空

        byte[] version = new byte[1];
        version[0] = 0x00;

        //拼接版本号
        byte[] var_pubhash = new byte[version.length + pubHash160.length];
        System.arraycopy(version,0,var_pubhash,0,version.length);
        System.arraycopy(pubHash160,0,var_pubhash,1,pubHash160.length);

        //取4个字节
        byte[] hash1 = Hash.SHA256(var_pubhash);
        byte[] hash2 = Hash.SHA256(hash1);
        //assert hash2 != null;

        byte[] check = new byte[4];
        System.arraycopy(hash2,0,check,0,check.length);

        //将哈希结果与双重哈希的前4个字节拼接
        byte[] var_pub_check = new byte[var_pubhash.length + check.length];
        System.arraycopy(var_pubhash,0,var_pub_check,0,var_pubhash.length);
        System.arraycopy(check,0,var_pub_check,var_pubhash.length,check.length);

        return Base58.encode(var_pub_check);


    }


    /**
     * 该方法生成非压缩格式的公钥数据  //由于java算法的某些原因，x、y会出现32或33个字节的情况,所以33只取下标0后面的字节
     * @return 非压缩公钥
     */
    public static byte[] toUncompressPukey(ECPoint point){

        byte[] xBytes = point.getAffineX().toByteArray();
        byte[] yBytes = point.getAffineY().toByteArray();
        //04+x+y=65
        byte[] pubKey = new byte[1+2*32];
        pubKey[0] = 04;

        if (xBytes.length == 32){
            //拷贝    需要的下标开始  容器名称    容器下标    需要的长度
            System.arraycopy(xBytes,0,pubKey,1,xBytes.length);
        } else if (xBytes.length == 33){
            System.arraycopy(xBytes,1,pubKey,1,32);
        }
        if (yBytes.length == 32){
            System.arraycopy(yBytes,0,pubKey,33,yBytes.length);
        } else if (yBytes.length == 33){
            System.arraycopy(yBytes,1,pubKey,33,32);
        }

        return pubKey;
    }


    /**
     * 校验生成的比特币地址是否符合规范
     * @param addr  要校验的字符串
     * @return  校验结果true表示符合规范，false表示不规范
     */
    public static boolean validateAddr(String addr){

        if ("".equals(addr) || addr == null){
            return false;
        }

        byte[] ver_pubhash_check = Base58.decode(addr);
        if (ver_pubhash_check.length < 4){
            return false;
        }

        byte[] check = new byte[4];
        System.arraycopy(ver_pubhash_check,ver_pubhash_check.length-4,check,0,4);

        byte[] ver_pubhash = new byte[ver_pubhash_check.length - 4];
        System.arraycopy(ver_pubhash_check,0,ver_pubhash,0,ver_pubhash.length);

        //哈希取前4字节
        byte[] hash1 = Hash.SHA256(ver_pubhash);
        byte[] hash2 = Hash.SHA256(hash1);
        if (hash2 == null) {
            return false;
        }

        byte[] check_sum = new byte[4];
        System.arraycopy(hash2,0,check_sum,0,check_sum.length);

        return Arrays.equals(check,check_sum);
    }


}
